﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace WpfControlsX.ControlX
{
    ////
    /// ----------------------------------------------------------------
    /// Copyright @BigWang 2023 All rights reserved
    /// Author      : BigWang
    /// Created Time: 2023/4/19 23:12:06
    /// Description :
    /// ----------------------------------------------------------------
    /// Version      Modified Time              Modified By     Modified Content
    /// V1.0.0.0     2023/4/19 23:12:06                     BigWang         首次编写         
    ///
    public abstract class AdornerElement : Control, IDisposable
    {
        protected FrameworkElement ElementTarget { get; set; }

        public static readonly DependencyProperty TargetProperty = DependencyProperty.Register(
            nameof(Target), typeof(FrameworkElement), typeof(AdornerElement), new PropertyMetadata(default(FrameworkElement), OnTargetChanged));

        private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctl = (AdornerElement)d;
            ctl.OnTargetChanged(ctl.ElementTarget, false);
            ctl.OnTargetChanged((FrameworkElement)e.NewValue, true);
        }

        [Bindable(true), Category("Layout")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public FrameworkElement Target
        {
            get => (FrameworkElement)GetValue(TargetProperty);
            set => SetValue(TargetProperty, value);
        }

        public static readonly DependencyProperty InstanceProperty = DependencyProperty.RegisterAttached(
            "Instance", typeof(AdornerElement), typeof(AdornerElement), new PropertyMetadata(default(AdornerElement), OnInstanceChanged));

        private static void OnInstanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is not FrameworkElement target)
            {
                return;
            }

            var element = (AdornerElement)e.NewValue;
            element.OnInstanceChanged(target);
        }

        protected virtual void OnInstanceChanged(FrameworkElement target)
        {
            Target = target;
        }

        public static void SetInstance(DependencyObject element, AdornerElement value)
        {
            element.SetValue(InstanceProperty, value);
        }

        public static AdornerElement GetInstance(DependencyObject element)
        {
            return (AdornerElement)element.GetValue(InstanceProperty);
        }

        public static readonly DependencyProperty IsInstanceProperty = DependencyProperty.RegisterAttached(
            "IsInstance", typeof(bool), typeof(AdornerElement), new PropertyMetadata(ValueBoxes.TrueBox));

        public static void SetIsInstance(DependencyObject element, bool value)
        {
            element.SetValue(IsInstanceProperty, ValueBoxes.BooleanBox(value));
        }

        public static bool GetIsInstance(DependencyObject element)
        {
            return (bool)element.GetValue(IsInstanceProperty);
        }

        protected virtual void OnTargetChanged(FrameworkElement element, bool isNew)
        {
            if (element == null) return;

            if (!isNew)
            {
                element.Unloaded -= TargetElement_Unloaded;
                ElementTarget = null;
            }
            else
            {
                element.Unloaded += TargetElement_Unloaded;
                ElementTarget = element;
            }
        }

        private void TargetElement_Unloaded(object sender, RoutedEventArgs e)
        {
            if (sender is FrameworkElement element)
            {
                element.Unloaded -= TargetElement_Unloaded;
                Dispose();
            }
        }

        protected abstract void Dispose();

        void IDisposable.Dispose() => Dispose();
    }
}